﻿using System.Runtime.InteropServices;
using System.Windows.Forms;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;

namespace GenericGameLibrary
{

    [StructLayout(LayoutKind.Sequential)]  //Ensures that it is sent in the order it is displayed, and not optimized
    public struct Message  //sets up how the message var will be sent to the peekmessage function, which will write to message in a specific order
    {
        public IntPtr hWnd;
        public Int32 msg;
        public IntPtr wParam;
        public IntPtr lParam;
        public uint time;
        public System.Drawing.Point p;
    }

    /// <summary>
    /// Fastloop takes a function and runs it continuously
    /// </summary>
    public class FastLoop
    {
        
        //UNSAFE ZONE//
        [System.Security.SuppressUnmanagedCodeSecurity]   //call C code in unsafe zone to check for system idle, opens User32.dll
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool PeekMessage(
           out Message msg,
           IntPtr hWnd,
           uint messageFilterMin,
           uint messageFilterMax,
           uint flags);
        //UNSAFE ZONE//

        public delegate void LoopCallback(double elapsedTime); //Container variable for function that will be looped continuously

        PreciseTimer _timer = new PreciseTimer();
        LoopCallback _callback; //stores sent function for future use

        //Constructor, takes in 1 argument (looping function)
        public FastLoop(LoopCallback callback)
        {
            _callback = callback; //set local _callback to function that is sent in args
            Application.Idle += new EventHandler(OnApplicationEnterIdle); //listens for system to be idle and runs the event handler OnApplicationEnterIdle
        }

        //Event handler for when the system is idle
        void OnApplicationEnterIdle(object sender, EventArgs e)
        {
            while (IsAppStillIdle()) //determines if the app is still idle, and if it is it continues to run
            {
                _callback(_timer.GetElapsedTime());  //runs the function that was sent as an arg
            }
        }

        private bool IsAppStillIdle() //function that looks for system idle  
        {
            Message msg;
            return !PeekMessage(out msg, IntPtr.Zero, 0, 0, 0); //if there is a message in queue, it returns true, so ! is needed to say that it is not idle if there is a message (send false)
        }
    }

}